package com.cd.music.utils;

import com.cd.music.annotation.RequestLimit;
import org.apache.commons.lang3.concurrent.BasicThreadFactory;
import org.apache.log4j.Logger;
import org.springframework.core.MethodParameter;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.util.HashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @author yxl 余秀良
 * @version 1.0
 * @description: 限制接口访问次数
 * @date 2018年03月01日  上午8:50
 * @address: 四川成都
 */
public final class RequestLimitUtil {
    private static final Logger logger = Logger.getLogger(RequestLimitUtil.class);

    private static HashMap<String, Integer> hashMap = new HashMap<>();

    public static void execute(MethodParameter methodParameter, HttpServletRequest request) {
        if (request == null) {
            throw new NullPointerException("缺少HttpServletRequest");
        }
        RequestLimit limit = methodParameter.getMethodAnnotation(RequestLimit.class);
        try {
            String ip = InetAddress.getLocalHost().getHostAddress();
            String url = request.getRequestURL().toString();
            String key = "req_limit_".concat(url).concat(ip);
            if (hashMap.get(key) == null || hashMap.get(key) == 0) {
                hashMap.put(key, 1);
            } else {
                hashMap.put(key, hashMap.get(key) + 1);
            }
            int count = hashMap.get(key);
            if (count > 0) {
                ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new BasicThreadFactory.Builder().namingPattern("request-limitImpl-schedule-pool-%d").daemon(true).build());
                //创建一个新的计时器任务。
                Runnable runnable = () -> {
                    hashMap.remove(key);
                    executorService.shutdown();
                };
                executorService.schedule(runnable, limit.time(), TimeUnit.MILLISECONDS);
            }
            if (count > limit.count()) {
                String msg = "用户IP[" + ip + "]访问地址[" + url + "]超过了限定的次数[" + limit.count() + "]";
                logger.info(msg);
                msg = "操作太频繁，请稍后再试.....";
                throw new RuntimeException(msg);
            }
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            logger.error("requestLimit方法发生异常: " + e.getMessage());
        }
    }

    /**
     * getIpAddr：获取用户真实IP
     *
     * @return ip
     */
    private static String getIpAddress(HttpServletRequest request) {
        String ip = request.getHeader("X-Real-IP");
        if (null != ip && !"".equals(ip.trim())
                && !"unknown".equalsIgnoreCase(ip)) {
            return ip;
        }
        ip = request.getHeader("X-Forwarded-For");
        if (null != ip && !"".equals(ip.trim())
                && !"unknown".equalsIgnoreCase(ip)) {
            // 多次反向代理后会有多个IP值，第一个为真实IP。
            int index = ip.indexOf(',');
            if (index != -1) {
                return ip.substring(0, index);
            } else {
                return ip;
            }
        }
        return request.getRemoteAddr();
    }
    private RequestLimitUtil() {
        throw new UnsupportedOperationException("这是一个工具类不能实例化");
    }
}
